fn create_box() {
    let _box1 = Box::new(3i32);
    // _box1在这里调用其析构函数，被释放；
}

fn main() {
    // 内存管理
    // RAII 资源获取即初始化, 因此每当对象超出范围时，都会调用其析构函数并释放其拥有的资源。
    let _box2 = Box::new(5i32);

    {
        let _box3 = Box::new(4i32);
        //_box3被释放；
    }

    for _ in 0u32..1_000 {
        create_box();
    }

    // 析构函数  Drop trait
    {
        struct ToDrop;

        impl Drop for ToDrop {
            fn drop(&mut self) {
                println!("ToDrop is being dropped");
            }
        }

        let _x = ToDrop;
        println!("Made a ToDrop!");
    }

    // 所有权
    // 因为变量负责释放自己的资源， 所以资源只能有一个 owner
    // 并非所有变量都拥有资源（eg: ref）
    // 移动
    // 按“值传递”或“赋值”，资源的所有权被转移 -- move
    // 移动后，之前的所有者就不能再使用了。
    // 移动后，可以为新变量设置可变性。
    {
        let immutable_box = Box::new(5u32);

        println!("immutable_box contains {}", immutable_box);

        // 移动变量，并修改可变性
        let mut mutable_box = immutable_box;

        println!("mutable_box contains {}", mutable_box);

        *mutable_box = 4;

        println!("mutable_box now contains {}", mutable_box);
    }

    // 部分移动
    // 堆内存的数据，部分转移；
    // 栈上的数据，会复制数据
    {
        #[derive(Debug)]
        struct Person {
            name: String,
            age: Box<u8>,
            height: usize,
        }

        let person = Person {
            name: String::from("Alice"),
            age: Box::new(20),
            height: 170,
        };

        let Person {
            name,
            ref age,
            height,
        } = person;

        println!("The person's age is {}", age);

        println!("The person's name is {}", name);

        println!("The person's height is {}", height);

        println!("The person's height is {}", height);

        // person不能使用，但person.age还可以使用
        // println!("The person struct is {:?}", person);
        println!("The person's age from person struct is {}", person.age);
    }

    // 借用
    {
        fn eat_box_i32(boxed_i32: Box<i32>) {
            println!("Destroying box that contains {}", boxed_i32);
        }

        fn borrow_i32(borrowed_i32: &i32) {
            println!("This int is: {}", borrowed_i32);
        }

        let boxed_i32 = Box::new(5_i32);
        let stacked_i32 = 6_i32;

        borrow_i32(&boxed_i32);
        borrow_i32(&stacked_i32);

        {
            let _ref_to_i32: &i32 = &boxed_i32;
            borrow_i32(_ref_to_i32);
            eat_box_i32(boxed_i32);
        }

        // eat_box_i32(boxed_i32);
    }

    // 可变性：
    // &mut T ：可变引用 ， 读写权限
    //&T: 不可变引用 ， 只读权限
    {
        #[allow(dead_code)]
        #[derive(Clone, Copy)]
        struct Book {
            author: &'static str,
            title: &'static str,
            year: u32,
        }

        fn borrow_book(book: &Book) {
            println!(
                "I immutably borrowed {} - {} edition",
                book.title, book.year
            );
        }

        fn new_edition(book: &mut Book) {
            book.year = 2014;
            println!("I mutably borrowed {} - {} edition", book.title, book.year);
        }

        let immutabook = Book {
            author: "X",
            title: "ABC",
            year: 2020,
        };

        let mut mutabook = immutabook;

        borrow_book(&immutabook);

        borrow_book(&mutabook);

        new_edition(&mut mutabook);
    }

    // 数据可以不可变地借用任意次数，但在不可变地借用时，原始数据不能可变地借用。
    // 一次只 允许一个可变借用。只有在可变引用最后一次使用后，才能再次借用原始数据。
    {
        struct Point {
            x: i32,
            y: i32,
            z: i32,
        }

        let mut point = Point { x: 0, y: 0, z: 0 };

        let borrowed_point = &point;
        let another_borrow = &point;

        println!(
            "Point has coordinates: ({}, {}, {})",
            borrowed_point.x, another_borrow.y, point.z
        );

        // 因为下面println还在使用不可变的变量，同一个变量不能同时是不可变，又是可变的。
        // let _mutable_borrow = &mut point;

        println!(
            "Point has coordinates: ({}, {}, {})",
            borrowed_point.x, another_borrow.y, point.z
        );

        let mutable_borrow = &mut point;

        mutable_borrow.x = 5;
        mutable_borrow.y = 2;
        mutable_borrow.z = 1;

        // 不能借用已经处于可变引用的原始不可变变量
        // let y = &point.y;
        // println!("Point Z coordinate is {}", point.z);

        println!(
            "Point has coordinates: ({}, {}, {})",
            mutable_borrow.x, mutable_borrow.y, mutable_borrow.z
        );

        // 使用完可变之后，再重新使用不可变引用
        let new_borrowed_point = &point;
        println!(
            "Point now has coordinates: ({}, {}, {})",
            new_borrowed_point.x, new_borrowed_point.y, new_borrowed_point.z
        );
    }

    // ref 模式
    {
        #[derive(Clone, Copy)]
        struct Point {
            x: i32,
            y: i32,
        }

        let c = 'Q';

        let ref ref_c1 = c;
        let ref_c2 = &c;

        println!("ref_c1 equals ref_c2: {}", *ref_c1 == *ref_c2);

        let point = Point { x: 0, y: 0 };

        let _copy_of_x = {
            let Point {
                x: ref ref_to_x,
                y: _,
            } = point;

            *ref_to_x
        };

        let mut mutable_point = point;

        {
            let Point {
                x: _,
                y: ref mut mut_ref_to_y,
            } = mutable_point;

            *mut_ref_to_y = 1;
        }

        println!("point is ({}, {})", point.x, point.y);
        println!(
            "mutable_point is ({}, {})",
            mutable_point.x, mutable_point.y
        );

        let mut mutable_tuple = (Box::new(5u32), 3u32);

        {
            let (_, ref mut last) = mutable_tuple;
            *last = 2u32;
        }

        println!("tuple is {:?}", mutable_tuple);
    }

    // 显式 生命周期： '
    {
        // 参数生命周期必须比函数长。
        fn print_refs<'a, 'b>(x: &'a i32, y: &'b i32) {
            println!("x is {} and y is {}", x, y);
        }

        let c = 5i32;

        fn failed_borrow<'c>(c: &'c i32) {
            let _x = 12;

            let y: &'c i32 = c;
            println!("{}", y);
        }

        let (four, nine) = (4, 9);

        print_refs(&four, &nine);

        failed_borrow(&c);

        println!("{}", c);
    }

    // 生命周期：函数
    {
        fn print_one<'a>(x: &'a i32) {
            println!("`print_one`: x is {}", x);
        }

        fn add_one<'a>(x: &'a mut i32) {
            *x += 1;
        }

        fn print_multi<'a, 'b>(x: &'a i32, y: &'b i32) {
            println!("`print_multi`: x is {}, y is {}", x, y);
        }

        fn pass_x<'a, 'b>(x: &'a i32, _: &'b i32) -> &'a i32 {
            x
        }

        let x = 7;
        let y = 9;

        print_one(&x);
        print_multi(&x, &y);

        let z = pass_x(&x, &y);
        print_one(z);

        let mut t = 3;
        add_one(&mut t);
        print_one(&t);
    }

    // 生命周期：方法
    {
        struct Owner(i32);

        impl Owner {
            fn add_one<'a>(&'a mut self) {
                self.0 += 1;
            }
            fn print<'a>(&'a self) {
                println!("`print`: {}", self.0);
            }
        }

        let mut owner = Owner(18);

        owner.add_one();
        owner.print();
    }

    // 生命周期： 结构体
    {
        #[derive(Debug)]
        struct Borrowed<'a>(&'a i32);

        #[allow(dead_code)]
        #[derive(Debug)]
        struct NamedBorrowed<'a> {
            x: &'a i32,
            y: &'a i32,
        }

        #[derive(Debug)]
        enum Either<'a> {
            Num(i32),
            Ref(&'a i32),
        }

        let x = 18;
        let y = 15;

        let single = Borrowed(&x);
        let double = NamedBorrowed { x: &x, y: &y };
        let reference = Either::Ref(&x);
        let number = Either::Num(y);

        println!("x is borrowed in {:?}", single);
        println!("x and y are borrowed in {:?}", double);
        println!("x is borrowed in {:?}", reference);
        println!("y is *not* borrowed in {:?}", number);
    }

    // 生命周期： trait
    {
        #[allow(dead_code)]
        #[derive(Debug)]
        struct Borrowed<'a> {
            x: &'a i32,
        }

        impl<'a> Default for Borrowed<'a> {
            fn default() -> Self {
                Self { x: &10 }
            }
        }

        let b: Borrowed = Default::default();
        println!("b is {:?}", b);
    }

    // 生命周期限定范围：  类型泛型限定范围， 使用"+"
    {
        use std::fmt::Debug; // Trait to bound with.

        #[derive(Debug)]
        struct Ref<'a, T: 'a>(&'a T);

        fn print<T>(t: T)
        where
            T: Debug,
        {
            println!("`print`: t is {:?}", t);
        }

        fn print_ref<'a, T>(t: &'a T)
        where
            T: Debug + 'a,
        {
            println!("`print_ref`: t is {:?}", t);
        }

        let x = 7;
        let ref_x = Ref(&x);

        print_ref(&ref_x);
        print(ref_x);
    }

    // 生命周期 - 强制缩短生命周期
    {
        fn multiply<'a>(first: &'a i32, second: &'a i32) -> i32 {
            first * second
        }

        fn choose_first<'a: 'b, 'b>(first: &'a i32, _: &'b i32) -> &'b i32 {
            first
        }

        let first = 2;

        {
            let second = 3;

            println!("The product is {}", multiply(&first, &second));
            println!("{} is the first", choose_first(&first, &second));
        }
    }

    // 生命周期： 'static
    // 表示引用指向的数据在运行程序的整个生命周期中都存在。它仍然可以被强制缩短寿命。
    //    有两种方法可以使变量具有'static生命周期，并且都存储在二进制文件的只读内存中：
    //        1.static用声明做一个常量。
    //        2.制作一个string具有 type: 的文字&'static str

    {
        static NUM: i32 = 18;

        // 返回对static NUM的引用，生命周期沿用输入参数的生命周期
        fn coerce_static<'a>(_: &'a i32) -> &'a i32 {
            &NUM
        }

        {
            let static_string = "I'm in read-only memory";
            println!("static_string: {}", static_string);
            // 超出范围，static string不在可以使用， 但数据仍然保存在二进制文件中。
        }

        {
            let lifetime_num = 9;

            let coerced_static = coerce_static(&lifetime_num);

            println!("coerced_static: {}", coerced_static);
        }

        println!("NUM: {} stays accessible!", NUM);

        // trait 绑定
        use std::fmt::Debug;

        fn print_it(input: impl Debug + 'static) {
            println!("'static value passed in is: {:?}", input);
        }

        let i = 5;
        print_it(i);

        // print_it(&i);
    }

    // 缺省的生命周期
    {
        fn elided_input(x: &i32) {
            println!("`elided_input`: {}", x);
        }

        fn annotated_input<'a>(x: &'a i32) {
            println!("`annotated_input`: {}", x);
        }

        fn elided_pass(x: &i32) -> &i32 {
            x
        }

        fn annotated_pass<'a>(x: &'a i32) -> &'a i32 {
            x
        }

        let x = 3;

        elided_input(&x);
        annotated_input(&x);

        println!("`elided_pass`: {}", elided_pass(&x));
        println!("`annotated_pass`: {}", annotated_pass(&x));
    }

    
}
